
package org.rescue.search;

import java.util.*;

import javax.swing.tree.DefaultMutableTreeNode;

import org.rescue.analysis.taxonomy.ConceptNodeData;
import org.rescue.data.extraction.*;


/** 
 * Dataset specifies the query terms and behavior expected for search, extraction
 * and classification, as well as the resulting documents and their concepts.
 */
public class Dataset {

	ArrayList<Document> documents = new ArrayList<Document>();
	DefaultMutableTreeNode taxonomy;
	String query;
	SearchBehavior searchBehavior;
	ExtractBehavior extractBehavior;
	ClassifyBehavior classifyBehavior;

	
	/**
	 * Get all the unique locationIds for the current dataset.
	 * @return A <code>String</code> of comma separated location ids. 
	 */
	public String getAllLocationsAsString() {
		// loop through docs to get location ids and add them to hash 
		HashSet<Integer> ids = new HashSet<Integer>();
		for (Document d : documents) {
			for (AnnotationSet as : d.getAnnotationSets()){
				for (Annotation a : as.getAnnotations()) {
					ids.add(a.getId());
				}
			}
		}
		// build the comma-separted value string
		StringBuffer locationIds = new StringBuffer();
		for (Integer id : ids){
			locationIds.append(id.toString() + ",");	
		}
		
		return locationIds.toString();
	}
	

	

	// return list of documents that contain speficied concepts
	public ArrayList<Document> matchDocsByConcepts(ArrayList<Integer> concepts) {
		
		ArrayList<Document> matches = new ArrayList<Document>();
		
		for (Document document : documents) {
			for (AnnotationSet as : document.getAnnotationSets()) {
				for (Integer annotationId : as.getAnnotationIds() ) {
					if (concepts.contains(annotationId)) {
						if (!matches.contains(document)){
							matches.add(document);
						}
					}
				}
			}
		}
		return matches;
	}

	
	public ArrayList<Integer> getTaxonomyChildrenIds(int concept) {
		
		// go through taxonomy and find the node with id = concept
		// then add all its descendents to childrenIds
		
		ArrayList<Integer> childrenIds = new ArrayList<Integer>();
		DefaultMutableTreeNode n = null;
		
		Enumeration e = taxonomy.breadthFirstEnumeration();
		while (e.hasMoreElements()) {
			DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.nextElement();
			ConceptNodeData nodeData = (ConceptNodeData)node.getUserObject();
			if(nodeData.getId() == concept) {
				n = node;
			}
		}

		Enumeration e2 = n.breadthFirstEnumeration();
		while (e2.hasMoreElements()) {
			DefaultMutableTreeNode node2 = (DefaultMutableTreeNode)e2.nextElement();
			ConceptNodeData nodeData2 = (ConceptNodeData)node2.getUserObject();
			childrenIds.add(nodeData2.getId());	
			
		}
		
		
		
		return childrenIds;
	}
	



	/*
	 * calculates and sets directCardinality value for nodes in taxonomy that
	 * correspond to concepts in the documents of this dataset.  Also sets cardinality of
	 * the root node.
	 */

	/*
	public void countConcepts() {

		// directCardinality of nodes - nodes may come from multiple taxonomies
		HashMap<Integer,Integer> conceptCounts = new HashMap<Integer,Integer>();  
				
		// loop through concepts of all the documents and keep tally
		for (Document document : documents) {
			for (AnnotationSet as : document.getAnnotationSets() ) {
				for (Integer annotationId : as.getAnnotationIds()) {
					if (conceptCounts.containsKey(annotationId)) {
						int currentCount = conceptCounts.get(annotationId);
						conceptCounts.put(annotationId, ++currentCount);
					}
					else {
						conceptCounts.put(annotationId, 1);
					}
				}
			}
		}
		// now do something with the counts
		System.out.println("concept direct cardinalities: \n" + conceptCounts);
		
		// for now assumes only one taxonomy, update for multiple
		countConceptsHelper(this.taxonomy, conceptCounts);
		ConceptNodeData conceptNodeData = (ConceptNodeData)taxonomy.getUserObject();
		conceptNodeData.setCard(100);		
		
	}

	// recursive method to get cardinality of a node
	public int countConceptsHelper(DefaultMutableTreeNode t, HashMap<Integer,Integer> conceptCounts) {

		ConceptNodeData conceptNodeData = (ConceptNodeData)t.getUserObject();
		int cardinality = 0;
		int directCardinality = 0;
		int conceptId = conceptNodeData.getId();
		
		if (conceptCounts.containsKey(conceptId)) {
			directCardinality = conceptCounts.get(conceptId);		
		}
		// else directCardinality defaults to 0
		
		if (t.isLeaf()) {		
				cardinality = directCardinality;			
		}
		else {
			Enumeration e = t.children();
			while (e.hasMoreElements()){
				cardinality += countConceptsHelper((DefaultMutableTreeNode)e.nextElement(), conceptCounts);
			}
		}
		cardinality = 0;
		conceptNodeData.setCard(cardinality);
		conceptNodeData.setDCard(directCardinality);
		
		return cardinality;
	}
	
	*/
	
	public void setSearchBehavior(SearchBehavior searchBehavior) {
		this.searchBehavior = searchBehavior;
	}
	
	public void setExtractBehavior(ExtractBehavior extractBehavior) {
		this.extractBehavior = extractBehavior;
	}
	
	public void setClassifyBehavior(ClassifyBehavior classifyBehavior) {
		this.classifyBehavior = classifyBehavior;
	}
	
	
	public ArrayList<Document> getDocuments() {
		return this.documents;
	}
	

	public void addDocument(Document d) {
		documents.add(d);
	}
	
	public void performSearch(int numResults)
	throws SearchException {
		this.documents = searchBehavior.search(query, numResults);		
	}
	
	public void performExtraction() {
		extractBehavior.extract(documents);
	}
	
	
	public void performClassification() {
		classifyBehavior.classify(documents);
		
	}
	

	public String getQuery() {
		return query;	
	}	
	public void setQuery(String q) {
		query = q;
	}
	
	

	public int getSize() {
		return documents.size();	
	}

	public DefaultMutableTreeNode getTaxonomy() {
		return taxonomy;
	}
	
	public void setTaxonomy(DefaultMutableTreeNode taxonomy) {
		this.taxonomy = taxonomy;
	}


	
	
	
	public String toString() {
		
		String s = "documents in the dataset: " + getSize() + "\n";
		s += "query string: " + getQuery() + "\n";
		
		for(Document sd : documents) {
			s += sd.toString() + "\n";	
		}
		
		return s;
	}
	
}















